package com.spring.security.config;

import com.alibaba.fastjson.JSON;
import com.spring.security.entity.UserEntity;
import com.spring.security.security.SecurityUser;
import com.spring.security.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    private Logger logger = LoggerFactory.getLogger(MySecurityConfig.class);
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                // 过滤静态资源
                .antMatchers("/static/**").permitAll().anyRequest().authenticated()
                // 配置登录接口与验证规则
                .and().formLogin().loginPage("/login").permitAll().successHandler(loginSuccessHandler())
                // 配置登出接口与验证规则
                .and().logout().permitAll().invalidateHttpSession(true).deleteCookies("JSESSIONID").logoutSuccessHandler(logoutSuccessHandler())
                // 控制 /login 最多可接入的数量
                .and().sessionManagement().maximumSessions(10).expiredUrl("/login");
        super.configure(http);
    }
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        // 初始化自定义登录方式与密码加密规则
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
        // 是否取消验证规则
        auth.eraseCredentials(false);
    }

    /**
     * 密码加密
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        // 加密为 4 - 31 级
        return new BCryptPasswordEncoder(4);
    }

    /**
     * 登出
     * @return
     */
    @Bean
    public LogoutSuccessHandler logoutSuccessHandler(){
        return new LogoutSuccessHandler() {
            @Override
            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response
                    , Authentication authentication) throws IOException, ServletException {
                try {
                    SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
                    logger.info("user go out success, userName: {}",securityUser.getUsername());
                }catch (Exception e){
                    logger.info("user go out error,message: {} ", JSON.toJSONString(e));
                }
            }
        };
    }

    /**
     * 登入
     * @return
     */
    @Bean
    public SavedRequestAwareAuthenticationSuccessHandler loginSuccessHandler(){
        return new SavedRequestAwareAuthenticationSuccessHandler(){
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response
                    , Authentication authentication) throws ServletException, IOException {
                    SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
                    logger.info("user login success,userName: " + securityUser.getUsername());
                    super.onAuthenticationSuccess(request,response,authentication);
            }
        };
    }
    @Bean
    public UserDetailsService userDetailsService(){
        return new UserDetailsService(){
            @Autowired
            private UserService userService;
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                UserEntity userEntity = userService.getUserByUserName(username);
                if(null == userEntity){
                    throw new UsernameNotFoundException("userName " + username + " not found");
                }
                logger.info("find one user userName: {}",username);
                return new SecurityUser(userEntity);
            }
        };
    }
}
